package com.yxx.service.Impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.yxx.constant.CommonConstant;
import com.yxx.constant.RedisConstant;
import com.yxx.entity.Article;
import com.yxx.entity.SiteConfig;
import com.yxx.entityModel.vo.response.*;
import com.yxx.enums.ArticleStatusEnum;
import com.yxx.mapper.*;
import com.yxx.service.BlogInfoService;
import com.yxx.service.RedisService;
import com.yxx.service.SiteConfigService;
import com.yxx.utils.UserAgentUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 博客业务信息实现类
 * @author yuxiangxun
 * @date 2025/1/21
 * @apiNote
 */
@Service
@Slf4j
public class BlogInfoServiceImpl implements BlogInfoService {

    @Resource
    private HttpServletRequest request;

    @Resource
    private RedisService redisService;

    @Resource
    private MessageMapper messageMapper;

    @Resource
    private ArticleMapper articleMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private CategoryMapper categoryMapper;

    @Resource
    private TagMapper tagMapper;

    @Resource
    private VisitLogMapper visitLogMapper;

    @Resource
    private SiteConfigService siteConfigService;

    @Override
    public void report() {
        // 获取用户ip
        String ipAddress = ServletUtil.getClientIP(request);
        log.info("用户ipAddress:{}",ipAddress);
        Map<String, String> userAgentMap = UserAgentUtils.parseOsAndBrowser(request.getHeader("User-Agent"));
        // 获取访问设备
        String os = userAgentMap.get("os");
        String browser = userAgentMap.get("browser");
        // 生成唯一用户标识
        String uuid = ipAddress + browser + os;
        String md5 = DigestUtils.md5DigestAsHex(uuid.getBytes());
        // 判断是否访问
        if(!redisService.hasSetValue(RedisConstant.UNIQUE_VISITOR,md5)){
            // 访客量 +1
            redisService.incr(RedisConstant.BLOG_VIEW_COUNT,1);
            // 保存唯一标识
            redisService.setSet(RedisConstant.UNIQUE_VISITOR,md5);
        }

    }

    /**
     * 查看后台信息
     * @return
     */
    @Override
    public BlogBackInfoResponse getBlogBackInfo() {
        // 访问量
        Integer viewCount = redisService.getObject(RedisConstant.BLOG_VIEW_COUNT);
        // 留言量
        Long messageCount = messageMapper.selectCount(null);
        // 用户量
        Long userCount = userMapper.selectCount(null);
        // 文章量
        Long articleCount = articleMapper.selectCount(new LambdaQueryWrapper<Article>()
                .eq(Article::getIsDelete, CommonConstant.FALSE));
        // 分类数据
        List<CategoryResponse> categoryRespList = categoryMapper.selectCategoryVO();
        // 标签数据
        List<TagOptionResponse> tagVOList = tagMapper.selectTagOptionList();
        // 查询用户浏览
        DateTime startTime = DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -7));
        DateTime endTime = DateUtil.endOfDay(new Date());
        List<UserViewResponse> userViewRespList = visitLogMapper.selectUserViewList(startTime, endTime);
        // 文章统计
        List<ArticleStatisticsResponse> articleStatisticsList = articleMapper.selectArticleStatistics();
        // 查询redis访问量前五的文章
        Map<Object, Double> articleMap = redisService.zReverseRangeWithScore(RedisConstant.ARTICLE_VIEW_COUNT, 0, 4);
        BlogBackInfoResponse blogBackInfoResp = BlogBackInfoResponse.builder()
                .articleStatisticsList(articleStatisticsList)
                .tagVOList(tagVOList)
                .viewCount(viewCount)
                .messageCount(messageCount)
                .userCount(userCount)
                .articleCount(articleCount)
                .categoryVOList(categoryRespList)
                .userViewVOList(userViewRespList)
                .build();
        if (CollectionUtils.isNotEmpty(articleMap)) {
            // 查询文章排行
            List<ArticleRankResponse> articleRankRespList = listArticleRank(articleMap);
            blogBackInfoResp.setArticleRankVOList(articleRankRespList);
        }
        return blogBackInfoResp;
    }

    /**
     * 查看博客信息
     * @return
     */
    @Override
    public BlogInfoResponse getBlogInfo() {
        // 博客访问量
        Integer count = redisService.getObject(RedisConstant.BLOG_VIEW_COUNT);
        String viewCount = Optional.ofNullable(count).orElse(0).toString();
        return BlogInfoResponse.builder()
                .articleCount(articleMapper.selectCount(new LambdaQueryWrapper<Article>()
                        .eq(Article::getIsDelete,CommonConstant.FALSE)
                        .eq(Article::getStatus, ArticleStatusEnum.PUBLIC.getStatus())))
                .categoryCount(categoryMapper.selectCount(null))
                .tagCount(tagMapper.selectCount(null))
                .viewCount(viewCount)
                .siteConfig(siteConfigService.getSiteConfig())
                .build();
    }

    /**
     * 查看关于我的信息
     * @return
     */
    @Override
    public String getAbout() {
        SiteConfig siteConfig = redisService.getObject(RedisConstant.SITE_SETTING);
        return siteConfig.getAboutMe();
    }

    /**
     * 查询文章排名
     * @param articleMap 文章浏览量信息
     * @return 文章排名
     */
    private List<ArticleRankResponse> listArticleRank(Map<Object,Double> articleMap){
        // 获取文章id List集合存储id -> articleIdList
        List<Integer> articleIdList = new ArrayList<>(articleMap.size());
        articleMap.forEach((key, value) -> articleIdList.add((Integer) key));
        // 查询文章信息（查询出文章id和文章标题即可，根据文章id集合查询）
        List<Article> articleList = articleMapper.selectList(
                new LambdaQueryWrapper<Article>()
                        .select(Article::getId, Article::getArticleTitle)
                        .in(Article::getId, articleIdList)
        );

        return articleList.stream()
                .map(article -> ArticleRankResponse.builder()
                        .articleTitle(article.getArticleTitle())
                        .viewCount(articleMap.get(article.getId()).intValue())
                        .build())
                .sorted(Comparator.comparingInt(ArticleRankResponse::getViewCount).reversed())
                .collect(Collectors.toList());
    }
}
